#include "Debug.hpp"
#include "Configuration.hpp"
#include "CacheManager.hpp"
#include "LRUCache.hpp"

#include <pthread.h>

namespace se {

CacheManager::CacheManager()
: _switchCache(0)
, _LRUCachePath(CONFIGURATION("LRUCachePath", std::string)) {
    int threadCount = CONFIGURATION("ThreadCountOfThreadPool", int);
    int cacheCapacity = CONFIGURATION("LRUCacheCapacity", int);

    _caches.resize(2 * threadCount, LRUCache(cacheCapacity));
    init();

    auto cacheListIterator = _caches.begin();
    while(cacheListIterator < _caches.end()) {  //循环地把主Cache的使用信息初始化到_cacheIsUsed中
        _cacheIsUsed.push_back(std::make_pair(false, cacheListIterator));
        cacheListIterator += 2;
    }
}

CacheManager::~CacheManager() {
    saveCacheToFile();
}

std::shared_ptr<nlohmann::json> CacheManager::find(const Key & key) {
    return getCache(::pthread_self()).find(key);
}

void CacheManager::insertToCache(const std::pair<Key, json> & record) {
    DEBUG_PRINT("insertToCache"); 
    if(!_copyMutex.trylock()) {
        pthread_t thid = pthread_self();
        getCache(thid).addRecord(record);
        _copyMutex.unlock();
    }
}

void CacheManager::init() {
    for(auto & cache : _caches) {
        cache.readFromFile(_LRUCachePath);
    }
}

void CacheManager::copyCache() {
    MutexLockGuard autoMutex(_copyMutex); 
    for(auto & bool_cacheIterator : _cacheIsUsed) {
        if(bool_cacheIterator.first) {
            (bool_cacheIterator.second + 1)->copyFrom(*bool_cacheIterator.second);
        }
    }
}

void CacheManager::switchCache() {
    MutexLockGuard autoMutex(_switchMutex);
    int temp = _switchCache;
    _switchCache = (++temp)%2;
}

LRUCache & CacheManager::getCache(unsigned long processId) {
    auto threadMapIterator = _threadMap.find(processId);
    if(threadMapIterator != _threadMap.end()) {
        MutexLockGuard autoMutex(_switchMutex);
        return *(threadMapIterator->second + _switchCache);
    }
    for(auto & bool_cacheIterator : _cacheIsUsed) {
        if(!bool_cacheIterator.first) {
            bool_cacheIterator.first = true;
            _threadMap.insert(std::make_pair(processId, bool_cacheIterator.second));
            MutexLockGuard autoMutex(_switchMutex);
            return *(bool_cacheIterator.second + _switchCache);
        }
    }

    return _caches[0];
}

void CacheManager::updateCache() {
    // for(auto & bool_cacheIterator : _cacheIsUsed) {
    //     if(bool_cacheIterator.first) {
    //         bool_cacheIterator.second->print();
    //     }
    // }

    copyCache();  //把缓存数据拷贝到备用缓存
    switchCache();  //切换至备用缓存
    
    for(auto & bool_cacheIterator : _cacheIsUsed) {  //把所有待更新数据集中至第一个缓存
        if(bool_cacheIterator.first) {
            bool_cacheIterator.second->movePendingUpdateListTo(_caches[0]);
        }
    }

    _caches[0].updateSelf();  //第一个缓存负责合并更新
    
    for(auto & bool_cacheIterator : _cacheIsUsed) {  //将更新后的缓存数据写回各个主缓存
        if(bool_cacheIterator.first) {
            bool_cacheIterator.second->copyFrom(_caches[0]);
        }
    }
    
    switchCache();  //切换至主缓存

    for(auto & bool_cacheIterator : _cacheIsUsed) {  //清空备用缓存数据，避免占用空间
        if(bool_cacheIterator.first) {
            (bool_cacheIterator.second + 1)->clear();
        }
    }
    
#if 1 
    //打印所有已启用的Cache
    for(auto & bool_cacheIterator : _cacheIsUsed) {
        if(bool_cacheIterator.first) {
            bool_cacheIterator.second->print();
        }
    }
#endif
}

void CacheManager::saveCacheToFile() {
    _caches[0].writeToFile(_LRUCachePath);
}

}  // end of namespace se
